//The implementation

var pageHolder = {}
var keyHolder = {}
var swapind = true
var POLLING_INTERVAL = 10000
var isMoving
var nodeStates = new Object()
var stateNodes = new Object()

function swap() {
	if (isMoving)
		return
		
	var pt1 = $("pageTable1")
	var pt2 = $("pageTable2")
	var t = $("titles")
	var cv = $("cv")
	var key = $("key")
	var moveTime = 500
	var moveSpeed = 18
	
	if (swapind) {
		isMoving = true
		if (pt2.firstChild) {
			move(pt1,null,moveTime,pt1.offsetLeft,pt1.offsetTop,-600,pt1.offsetTop,moveSpeed)
			move(pt2,null,moveTime,pt2.offsetLeft,pt2.offsetTop,450,pt2.offsetTop,moveSpeed)
		} else {
			move(pt1,null,moveTime,pt1.offsetLeft,pt1.offsetTop,500,pt1.offsetTop,moveSpeed)
			move(pt2,null,moveTime,pt2.offsetLeft,pt2.offsetTop,1020,pt2.offsetTop,moveSpeed)
		}
		move(t,null,moveTime,t.offsetLeft,t.offsetTop,10,t.offsetTop,moveSpeed)
		move(cv,null,moveTime,cv.offsetLeft,cv.offsetTop,10,cv.offsetTop,moveSpeed)
		move(key,function() {isMoving=false},moveTime,key.offsetLeft,key.offsetTop,10,key.offsetTop,moveSpeed)
	}
	else {
		isMoving = true
		move(pt1,null,moveTime,pt1.offsetLeft,pt1.offsetTop,10,pt1.offsetTop,moveSpeed)
		move(pt2,null,moveTime,pt2.offsetLeft,pt2.offsetTop,1020,pt2.offsetTop,moveSpeed)
		move(t,null,moveTime,t.offsetLeft,t.offsetTop,Browser.width()*0.5,t.offsetTop,moveSpeed)
		move(cv,null,moveTime,cv.offsetLeft,cv.offsetTop,Browser.width()*0.5,cv.offsetTop,moveSpeed)
		move(key,function() {isMoving=false},moveTime,key.offsetLeft,key.offsetTop,Browser.width()*0.5,key.offsetTop,moveSpeed)
	}
	
	pt = null
	t = null
	cv = null
	key = null
	moveTime = null
	
	swapind = !swapind
}

function startG(nodeName) {
	//clientName = nodeName
	loadNodeStates("queue")
	loadGQueue("queue")
	window.setInterval(new Function("loadGQueue(\"queue\")"),POLLING_INTERVAL)
	window.setTimeout(reload,(30*60*1000))
	var monNodes = ["Composing","Engraving"]
	var t
	for (var gi=0;gi<monNodes.length;gi++) {
		t = $N("div")
		t.style.position="absolute"
		t.style.left=(gi)*150+30 + "px"
		t.style.width="150px"
		t.style.textAlign="center"
		t.style.fontSize="14pt"
		t.style.top=$("titles").offsetTop+"px"
		t.appendChild($T(monNodes[gi]))
		$("titles").appendChild(t)
	}
	t = null
	monNodes = null
}	

function loadNodeStates(queueName) {
	loadNodeState("Composing",queueName)
	loadNodeState("Engraving",queueName)
}

function loadNodeState(nodeName, queueName) {
	var url = "prodMon.ashx?action=<action><getQueue node=\"" + escape(nodeName) + "\"/></action>&queue=" + escape(queueName)
	quickGET(url,saveNodesStates,debugResponse)
}

function saveNodesStates(id,obj,text,time,req) {
	nodeStates[obj.nodeName] = new Array()
	for (var si in obj.states) {
		if (obj.states[si].stateName)
			nodeStates[obj.nodeName].push(obj.states[si].stateName)
	}
	var n = nodeStates[obj.nodeName]
	for (var si in n) {
		if (!stateNodes[n[si]]) {
			stateNodes[n[si]] = new Array()
		}
		stateNodes[n[si]].push(obj.nodeName)
	}
	req=null
}

function loadGQueue(queueName) {
	swap()
	var url = "prodMon.ashx?action=<action><getQueue node=\"" + escape("Editorial") + "\"/></action>&queue=" + escape(queueName)
	quickGET(url,showGQueue,debugResponse)
	//url = "prodMon.ashx?action=<action><getQueue node=\"" + escape("Engraving") + "\"/></action>&queue=" + escape(queueName)
	//quickGET(url,showGQueue,debugResponse)
	url = null
}

function rgbaTorgb(color) {
	return color.replace(/,[0-9\.]*\)/,")").replace("rgba","rgb")
}

function showGQueue(id,obj,text,time,req) {
	var ce = $("cv")
	var ctx = ce.getContext("2d")
	var nodePos = { "Editorial" : 0, "Composing" : 1, "Engraving" : 2 }
	var pos = nodePos[obj.nodeName]
	
	var queues = new Object()
	
	var pages = obj.pages.clone(true).sort(new Function("a","b","if (a['delete']=='delete' || b['delete']=='delete') {return 0} else {return a._sort-b._sort}"))
	var allPageCount = pages.length
	var states = obj.states.clone(true)
	pages=pages.filter(function(obj) {if (!obj["delete"]) {return true}})
	var values = []
	var counts = []
	var sections = []
	
	//obj.states[0].alertObjectProperties()
	
	var key = $("key")
	for (var os in states) {if (!Array[os] && states[os].color) {
		if (!keyHolder[states[os].stateName]) {
			var s = $N("div",$T(states[os].stateName),{"style":"margin-bottom:2px"})
			s.style.borderLeft = "10px solid"
			var c= states[os].color.replace(/,[0-9\.]*\)/,")").replace("rgba","rgb")
			s.style.borderColor = c
			key.appendChild(s)
			keyHolder[states[os].stateName] = true
		}
	}}
	key = null
	
	for (var pi=0;pi<pages.length;pi++) {
		if (!sections.contains(pages[pi].pageSection))
			sections.push(pages[pi].pageSection)
	}
	sections.sort()
	
	//show page table
	var selem
	for (var si=0;si<sections.length;si++) {
		selem = $("sec" + sections[si])
		if (!selem) {
			sdiv = $N("div")
			stbl = $N("table")
			stbl.style.margin="0px"
			stbl.style.padding="0px"
			stbl.style.borderCollapse="collapse"
			selem = $N("tbody")
			selem.id = "sec" + sections[si]
			sdiv.style.position="absolute"
			sdiv.style.left = 20+si*140 + "px"
			sdiv.style.borderRight = "1px solid #c9c9c9"
			sdiv.style.paddingRight = "2px"
			sdiv.style.top = "10px"
			sdiv.style.margin="2px"
			sdiv.style.fontSize="12pt"
			selem = stbl.appendChild(selem)
			sdiv.appendChild(stbl)
			if (sections[si]>"D") {
				sdiv.style.left = (sdiv.style.left.substring(0,sdiv.style.left.length-2) - (140*3)) + "px"
				$("pageTable2").appendChild(sdiv)
			} else {
				$("pageTable1").appendChild(sdiv)
			}
		}
		for (var pi=0;pi<pages.length;pi++) {
			var page = pages[pi]
			if (sections[si]==page.pageSection) {
				var ph = pageHolder[page.pageName]
				if (!ph) {
					ph = $N("tr")
					ph.style.borderCollapse="collapse"
					ph.id = page.pageName.replace(/ /g,"")
					//ph.style.padding="2px"
					ph=selem.appendChild(ph)
					pageHolder[page.pageName]=ph
				}
				while (ph.firstChild)
					ph.removeChild(ph.lastChild)
				var tok = $N("img",null,{"style":"font-size:12pt;margin-left:6px;height:1em;width:1em;","height":"1em","width":"1em"}) //token for status indication
				switch (page.pageStatus) {
					case "complete":
						tok.src="Images/done.png"
						break
					case "late":
						tok.src="Images/bad.png"
						break
					case "ontime":
						tok.src="Images/good.png"
						break
				}
				var s = $N("span",$T(page.pageName))
				s.style.borderLeft = "10px solid"
				for (var os in states) {
					if (states[os].stateName && states[os].stateName==page.pageState) {
						var c= states[os].color.replace(/,[0-9\.]*\)/,")").replace("rgba","rgb")
						s.style.borderColor = c
					}
				}
				ph.appendChild($N("td",s))
				ph.appendChild($N("td",tok))
				//ph.appendChild($N("td",$N("small",$T(obj.nodeName))))
				//ph.appendChild($N("td",$T(page._sort)))
			}
		}
	}
	selem = null
	
	for (var ni in nodeStates) { if (!Object[ni]) {
		pos = nodePos[ni]
		var nodePages = pages.filter(
			new Function("val","i","array","return nodeStates[\"" + ni + "\"].contains(val.pageState)")
		)
	
		//show state bucket pie
		var stateColors = []
		var state
		for (var si=0;si<states.length;si++) {
			state = states[si]
			values[si]=0
			counts[si]=[]
			stateColors[si]=state.color
			for (var pi=0;pi<nodePages.length;pi++) {
				var page = nodePages[pi]
				if (page.pageState==state.stateName) {
					values[si]=values[si]+1
				}
			}
		}
		state = null
		
		//alert(stateColors.toSource())
		var p = new PieChart(values)
		p.center = { "x":(pos)*150-50, "y":50 }
		p.colors = stateColors.clone(true) //[ "rgba(128,224,128,.65)", "rgba(224,128,128,.65)", "rgba(128,128,224,0.65)" ]
		try {p.render(ctx)} catch(ex) {}
		
		//show status pie
		var statuses = ["complete","late","ontime"]
		var statCounts = [0,0,0]
		var status
		for (var si=0;si<statuses.length;si++) {
			status = statuses[si]
			for (var pi=0;pi<nodePages.length;pi++) {
				var page = nodePages[pi]
				if (page.pageStatus==status) {
					statCounts[si]=statCounts[si]+1
				}
			}
		}
		status = null
		
		var p = new PieChart(statCounts)
		p.center = { "x":(pos)*150-50, "y":325 }
		p.colors = [ "rgba(0,255,0,.65)", "rgba(255,0,0,.65)", "rgba(0,0,255,.65)" ]
		try {p.render(ctx)} catch(ex) {}

		//find the min/max times
		var mint = (new Date()).getTime() //-(3*60*60*1000)  //three hours ago
		var maxt = mint
		var et
		var dt
		for (var pi=0;pi<nodePages.length;pi++) {
			for (var hi=0;hi<nodePages[pi].history.length;hi++) {
				et = Date.parse(nodePages[pi].history[hi].entryTime.replace("T"," ").replace(/-/g,"/"))
				dt = Date.parse(nodePages[pi].history[hi].deadlineTime.replace("T"," ").replace(/-/g,"/"))
				mint = Math.min(mint,Math.min(et,dt))
				maxt = Math.max(mint,Math.max(et,dt))
			}
		}
		//only graph time over the last 3 hours
		mint = Math.max((new Date()).getTime()-(3*60*60*1000),mint)
		
		//count items in each state for every ten minute interval
		var i = 0
		var state
		for (var t=mint+600000;t<=maxt;t+=600000) {
			
			for (var si=0;si<states.length;si++) {
				state = states[si]
				counts[si][i]=0
				for (var pi=0;pi<nodePages.length;pi++) {
					var page = nodePages[pi]
					for (var hi=0;hi<page.history.length;hi++) {
						if (page.history[hi].pageState==state.stateName && otp(page.history[hi].entryTime)<t && (!page.history[hi-1] || otp(page.history[hi].entryTime)>=mint)) {
							counts[si][i]=counts[si][i]+1
						}
					}
				}
			}
			mint = t
			i++
		}
		state = null
		
		ctx.fillStyle="#EEE"
		ctx.fillRect((pos-1)*150+25,150,145,100)
		var l
		var colors = stateColors.clone(true) //[ "rgba(128,224,128,.65)", "rgba(224,128,128,.65)", "rgba(128,128,224,0.65)" ]
		for (var j=0;j<counts.length;j++) {
			l = new LineChart(counts[j])
			l.origin={ "x":(pos-1)*150+25, "y":150 }
			l.min = 0
			l.max = allPageCount //pages.length
			l.width = 145
			l.height = 100
			l.style = colors[j]
			l.gridStep = l.max/8
			try {l.render(ctx)} catch(ex) {}
		}
		l = null
	}}
	req=null
}
function otp(t) { 
	return Date.parse(t.replace("T"," ").replace(/-/g,"/"))
}

function showClockQueue(id,obj,text,time,req) {
	//alert(Date.parse(obj.pages[0].history[0].entryTime.replace(/T/," ").replace(/-/g,"/")))
	var ce = $("cv")
	var ctx = ce.getContext("2d")
	
	var pages = obj.pages.clone(true)
				
	for (var pi=0;pi<pages.length;pi++) {
		var page = pages[pi]
		var times = []
		var dls = []
		for (var hi=0;hi<page.history.length;hi++) {
			dls.push(Date.parse(page.history[hi].entryTime.replace("T"," ").replace(/-/g,"/")))
			dls.push(Date.parse(page.history[hi].deadlineTime.replace("T"," ").replace(/-/g,"/")))
			times.push(Date.parse(page.history[hi].entryTime.replace("T"," ").replace(/-/g,"/")))
			times.push((page.history[hi+1]) ? Date.parse(page.history[hi+1].entryTime.replace("T"," ").replace(/-/g,"/")) : (new Date()).getTime())
		}
		var p = new ClockChart(times,dls)
		p.center = { "x":(pi+1)*100-50, "y":50 }
		p.render(ctx)
	}
	req=null
}







//================================================================================
//       The graphing guts
//================================================================================
function ClockChart(times, deadlines) {
	this.times = times
	this.deadlines = deadlines
	this.radius = 50
	this.center = { "x":50, "y":50 }
}
ClockChart.prototype.render = function(ctx) {
	ctx.shadowColor = "rgba(32,32,32,0.8)"
	ctx.shadowOffsetX = 4
	ctx.shadowOffsetY = 4
	
	ctx.shadowBlur = 7
	ctx.beginPath()
	ctx.fillStyle = "rgb(255,255,255)"
	ctx.arc(this.center.x,this.center.y,this.radius,0,2*Math.PI,1)
	ctx.fill()
	
	ctx.shadowBlur=0
	ctx.shadowOffsetX=0
	ctx.shadowOffsetY=0
	ctx.shadowColor="rgb(255,255,255)"
	for(var tick=0;tick<=2*Math.PI;tick+=Math.PI/12) {
		ctx.beginPath()
		ctx.strokeStyle = "rgb(128,128,128)"
		ctx.lineWidth = 1
		ctx.arc(this.center.x, this.center.y, this.radius, tick, tick, 0)
		ctx.arc(this.center.x, this.center.y, this.radius*0.9, tick, tick, 0)
		ctx.stroke()
	}
	
	var angles = []
	var dayLength = 86400000
	
	var today = new Date()
	today.setHours(0,0,0,0)
	var thisDayValue = today.getTime()
	var nextDayValue = thisDayValue + dayLength
	
	this.times.sort()
	this.times.filter(new Function ("obj", "index", "array", "if (obj>=" + thisDayValue + " && obj<= " + nextDayValue + ") {return true}"))
	
	for (var ti=0;ti<this.times.length;ti++) {
		var A = 2 * Math.PI * (this.times[ti]-thisDayValue)/dayLength
		angles.push(A-Math.PI/2)
	}
	
	ctx.shadowBlur=0
	ctx.shadowColor = "rgb(255,255,255)"
	ctx.shadowOffsetX = 0
	ctx.shadowOffsetY = 0
	ctx.beginPath()
	ctx.fillStyle = "rgba(208,208,255,0.8)"
	ctx.lineWidth = 1
	//alert(angles.toSource())
	for (var ai=0;ai<angles.length-1;ai+=2) {
		ctx.arc(this.center.x,this.center.y,this.radius,angles[ai],angles[ai+1],0)
		ctx.lineTo(this.center.x,this.center.y)
		ctx.closePath()
		ctx.fill()
		//ctx.fillStyle="rgb(" + Math.random() * 255 + ",0,0)"
		//ctx.fill()
	}
	
	var angles = []
	
	this.times.sort()
	this.times.filter(new Function ("obj", "index", "array", "if (obj>=" + thisDayValue + " && obj<= " + nextDayValue + ") {return true}"))
	
	for (var ti=0;ti<this.deadlines.length;ti++) {
		var A = 2 * Math.PI * (this.deadlines[ti]-thisDayValue)/dayLength
		angles.push(A-Math.PI/2)
	}
	
	ctx.shadowBlur=0
	ctx.shadowColor = "rgb(255,255,255)"
	ctx.shadowOffsetX = 0
	ctx.shadowOffsetY = 0
	ctx.fillStyle = "rgba(208,208,208,0.8)"
	ctx.lineWidth = 1
	for (var ai=0;ai<angles.length-1;ai+=2) {
		ctx.beginPath()
		ctx.strokeStyle = "rgb(0,255,0)"
		ctx.arc(this.center.x,this.center.y,this.radius,angles[ai],angles[ai],0)
		ctx.lineTo(this.center.x,this.center.y)
		ctx.stroke()
		ctx.beginPath()
		ctx.arc(this.center.x,this.center.y,this.radius,angles[ai+1],angles[ai+1],0)
		ctx.lineTo(this.center.x,this.center.y)
		ctx.strokeStyle = "rgb(255,0,0)"
		ctx.stroke()
		//ctx.fillStyle="rgb(" + Math.random() * 255 + ",0,0)"
		//ctx.fill()
	}
	
	var A = 2 * Math.PI * ((new Date()).getTime()-thisDayValue)/dayLength
	ctx.beginPath()
	ctx.arc(this.center.x,this.center.y,this.radius*0.8,A,A,0)
	ctx.lineTo(this.center.x,this.center.y)
	ctx.lineWidth = 3
	ctx.strokeStyle = "rgb(128,128,128)"
	ctx.stroke()
}

function PieChart(values) {
	var total = 0
	for (var vi=0;vi<values.length;vi++)
		total+=values[vi]
	this.total = total
	this.values = values
	this.radius = 50
	this.center = { "x":50, "y":50 }
	this.colors = []
	for (var i=0;i<values.length;i++)
		this.colors.push("rgba(" + parseInt(Math.random() * 255) + "," + parseInt(Math.random() * 255) + "," + parseInt(Math.random() * 255) + ",0.65)")
}
PieChart.prototype.render = function(ctx) {

	//draw base circle with shadow
	ctx.shadowColor = "rgba(32,32,32,0.8)"
	ctx.shadowOffsetX = 4
	ctx.shadowOffsetY = 4
	
	ctx.shadowBlur = 7
	ctx.beginPath()
	ctx.fillStyle = "rgb(255,255,255)"
	ctx.arc(this.center.x,this.center.y,this.radius,0,2*Math.PI,1)
	ctx.fill()
	
	//draw tickmarks on circle
	ctx.shadowBlur=0
	ctx.shadowOffsetX=0
	ctx.shadowOffsetY=0
	ctx.shadowColor="rgb(255,255,255)"
	for(var tick=0;tick<=2*Math.PI;tick+=Math.PI/12) {
		ctx.beginPath()
		ctx.strokeStyle = "rgb(128,128,128)"
		ctx.lineWidth = 1
		ctx.arc(this.center.x, this.center.y, this.radius, tick, tick, 0)
		ctx.arc(this.center.x, this.center.y, this.radius*0.9, tick, tick, 0)
		ctx.stroke()
	}
	
	//calculate pie piece angles
	var angles = [0]
	
	//this.values.sort()
	
	var pv = 0
	for (var vi=0;vi<this.values.length;vi++) {
		pv += this.values[vi]
		var A = 2 * Math.PI * (pv)/this.total
		if (A==2*Math.PI) //IECanvas displays no arc in this case
			A=2*Math.PI-0.001
		angles.push(A)
	}
	
	angles.push(2*Math.PI)
	
	//draw pie pieces
	ctx.shadowBlur=0
	ctx.shadowColor = "rgb(255,255,255)"
	ctx.shadowOffsetX = 0
	ctx.shadowOffsetY = 0
	ctx.lineWidth = 1
	//alert(angles.toSource())
	for (var ai=0;ai<angles.length-2;ai++) {
		ctx.beginPath()
		ctx.fillStyle=this.colors[parseInt(ai)]
		ctx.arc(this.center.x,this.center.y,this.radius,angles[ai],angles[ai+1],0)
		ctx.lineTo(this.center.x,this.center.y)
		//ctx.fillStyle="rgba(" + parseInt(Math.random() * 255) + "," + parseInt(Math.random() * 255) + "," + parseInt(Math.random() * 255) + ",0.65)"
		ctx.fill()
	}
}
function LineChart(data) {
	this.data = data
	this.origin = { "x":200, "y":200 }
	this.height = 200
	this.width = 200
	this.filled = true
	var pts = this.data.length
	var max = this.data[0]
	var min = this.data[0]
	for (var di=1;di<pts;di++) {
		max = Math.max(max,this.data[di])
		min = Math.min(min,this.data[di])
	}
	this.max=max
	this.min=min
	this.style = "rgba(" + parseInt(Math.random() * 255) + "," + parseInt(Math.random() * 255) + "," + parseInt(Math.random() * 255) + ",0.40)"
	this.gridOn = true
	this.gridStep = 3
}
LineChart.prototype.render = function(ctx) {
	var pts = this.data.length
	var xWidth = this.width/(pts-1)
	var yHeight = (this.height+0.0)/(this.max)
	var yOffset = this.min
	var y
	
	ctx.beginPath()
	ctx.moveTo(this.origin.x, this.origin.y+this.height)
	for (var di=0;di<pts;di++) {
		y=Math.min(this.height,this.data[di]*yHeight)
		ctx.lineTo(this.origin.x+di*xWidth, this.origin.y+this.height-y)
	}
	ctx.lineTo(this.origin.x+(pts-1)*xWidth,this.origin.y+this.height)
	ctx.fillStyle=this.style
	ctx.strokeStyle=this.style
	if (this.filled)
		ctx.fill()
	else
		ctx.stroke()
	
	if (this.gridOn) {
		ctx.strokeStyle="#FFF"
		for (var y=0;y<this.max;y+=this.gridStep) {
			ctx.beginPath()
			ctx.moveTo(this.origin.x,this.origin.y+this.height-y*yHeight)
			ctx.lineTo(this.origin.x+this.width,this.origin.y+this.height-y*yHeight)
			ctx.stroke()
		}
	}
}